// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "VideoEncoder.h"
#include <thread>
#include <cstring>
#include <fstream>
#include <queue>
#include "Communication/PacketManager.h"
#include "HWSecure/include/securec.h"
#include "cjson/json/cJSON.h"
#include "VideoSocketAgent.h"
#include "VideoAgent.h"

namespace {
    constexpr uint32_t REPEAT_TOTAL_FRAMES = 4;
    constexpr uint32_t QUEUE_FOR_ENCODE = 2;
    constexpr uint32_t SLEEP_FOR_RECEIVE = 500;
    constexpr uint32_t SLEEP_FOR_ENCODE = 500;
    constexpr int ONE_SECOND_TO_US = 1000000;
    constexpr int ONE_SECOND_TO_MS = 1000;
    constexpr uint32_t FRAMERATE_30 = 30;
    constexpr uint32_t FRAMERATE_60 = 60;
    constexpr uint32_t FRAMERATE_30_WITHOUT_REPEAET = 303;
    constexpr uint32_t FRAMERATE_60_WITHOUT_REPEAET = 606;

    const char* CONF_KEY_FPS = "fps";
    const char* CONF_KEY_REPEAT_FPS = "repeat_fps";
    const char* CONF_KEY_BIT_RATE = "bitrate";
    const char* CONF_KEY_GOP = "gop";
    const char* CONF_KEY_PROFILE = "profile";
    const char* CONF_KEY_RC_MODE = "rcmode";
    const char* CONF_KEY_KEY_FRAME = "key_frame";
    const char* CONF_KEY_WIDTH = "width";
    const char* CONF_KEY_HEIGHT = "height";
    const char* CONF_KEY_ENCODER_TYPE = "encoder_type";
    const char* CONF_KEY_FRAME_TYPE = "frame_type";
    const char* CONF_KEY_THREAD_COUNT = "thread_cnt";
    const char* CONF_KEY_THREAD_TYPE = "thread_type";
    const char* CONF_KEY_DISREPEAT = "disrepeat";
    const char* CONF_KEY_PRESET = "preset";
    const char* CONF_KEY_TUNE = "tune";
}

/*
 * @功能描述：获取当前时间精确到us
*/
static long GetCurrentTimeUs() {
    timespec now;
    (void)clock_gettime(CLOCK_REALTIME, &now);
    return reinterpret_cast<long>(now.tv_sec * ONE_SECOND_TO_US + now.tv_nsec / ONE_SECOND_TO_MS);
}

/*
 * @功能描述：获取当前时间精确到ms
*/
static long GetCurrentTimeMs()
{
    constexpr int oneSecond = 1000;
    timespec now;
    if(clock_gettime(CLOCK_REALTIME, &now) != 0){
        ERR("get time failed");
    }
    return reinterpret_cast<long>(now.tv_sec * oneSecond + now.tv_nsec / (oneSecond * oneSecond));
}

/**
 * @功能描述：构造函数
 */
VideoEncoder::VideoEncoder(std::function<void()> fnCallback)
{
    m_callback = fnCallback;
}
/**
 * @功能描述：析构函数
 */
VideoEncoder::~VideoEncoder()
{
    m_callback == nullptr;
    m_recvFlag = false;
    m_encodeFlag = false;
}

void RcvTaskentry(VideoEncoder* videoEncoder)
{
    INFO("RcvTaskentry in......");
    if (videoEncoder != nullptr) {
        while (videoEncoder->m_recvStatus == ENCODER_RECV_STATUS::ENCODER_RECEIVE_RUNNING) {
            VideoData videoData = VideoSocketAgent::GetInstance()->GetNextVideoData();
            VMIMsgType dataType = videoData.dataType;
            uint32_t dataLen = videoData.dataLength;
            uint8_t* payLoad = videoData.data;
            if (payLoad == nullptr || dataLen == 0) {
                DBG("recv data is null");
                (void)usleep(SLEEP_FOR_RECEIVE);
                continue;
            }

            videoEncoder->AddVideoDataToQueue(videoData);
            if (dataType == VMIMsgType::VideoStreamYuv) {
                std::pair<uint8_t*, uint32_t> yuvData = {payLoad, dataLen};
                videoEncoder->UpdateLastFrameData(yuvData);
            }
        }
    }
    videoEncoder->m_recvFlag = false;
    INFO("RcvTaskentry finished......");
}

void EncodeTaskentry(VideoEncoder* videoEncoder)
{
    INFO("EncodeTaskentry in......");
    if (videoEncoder != nullptr) {
        while (videoEncoder->m_recvStatus == ENCODER_RECV_STATUS::ENCODER_RECEIVE_RUNNING) {
            uint32_t yuvCount = videoEncoder->GetEncodeQueueYUVCount();
            if (yuvCount < 1) {
                videoEncoder->HandleRepeat();
            }

            if (videoEncoder->IsQueueEmpty()) {
                (void)usleep(SLEEP_FOR_ENCODE);
                continue;
            }

            VideoData videoData = videoEncoder->PopEncodeQueue();
            if (videoData.dataType == VMIMsgType::VideoStreamYuv) {
                if (yuvCount <= QUEUE_FOR_ENCODE) {
                    videoEncoder->Handle(videoData.data, videoData.dataLength);
                } else {
                    INFO("start to drop frame!");
                }
            } else if (videoData.dataType == VMIMsgType::VideoEncodeConf) {
                videoEncoder->InitEncodeParam(videoData.data, videoData.dataLength);
            }
            VmiFreeBuffer(videoData.data);
        }
        videoEncoder->DestroyVideoEngine();
    }
    videoEncoder->m_encodeFlag = false;
    INFO("EncodeTaskentry finished......");
}

/**
 * @功能描述：初始化编码引擎、注册回调、启动编码
 */
bool VideoEncoder::Start()
{
    if (m_callback == nullptr) {
        ERR("m_callback is null");
        return false;
    }
    this->m_recvStatus = ENCODER_RECV_STATUS::ENCODER_RECEIVE_RUNNING;
    m_recvTask = new (std::nothrow) std::thread(RcvTaskentry, this);
    m_encodeTask = new (std::nothrow) std::thread(EncodeTaskentry, this);
    if (m_recvTask == nullptr || m_encodeTask == nullptr) {
        ERR("Subthread start failed");
        return false;
    }
    m_recvFlag = true;
    m_encodeFlag = true;
    return true;
}

/**
 * @功能描述：销毁编码引擎
 */
void VideoEncoder::ForceStop()
{
    this->m_recvStatus = ENCODER_RECV_STATUS::ENCODER_RECEIVE_STOP;
    INFO("ForceStop in......");
    if (m_recvTask != nullptr) {
        m_recvTask->join();
        delete m_recvTask;
        m_recvTask = nullptr;
    }
    if (m_encodeTask != nullptr) {
        m_encodeTask->join();
        delete m_encodeTask;
        m_encodeTask = nullptr;
    }
    INFO("Subthread has been destroyed");

    PacketManager::GetInstance()->ClearPkt();
    ClearEncodeQueue();
    ClearLastFrame();

    INFO("ForceStop end......");
}

bool VideoEncoder::ParseCjsonConfig(std::string conf, VideoEncoderParam& videoEncoderParam)
{
    INFO("Received CJSON string is %s", conf.c_str());
    cJSON *cjsonConf = cJSON_Parse(conf.c_str());
    if (nullptr == cjsonConf) {
        ERR("Parse encode config failed.");
        return false;
    }

    cJSON *fpsItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_FPS);
    if (nullptr == fpsItem) {
        ERR("Parse fps failed.");
    } else {
        videoEncoderParam.frameRate = fpsItem->valueint;
    }

    cJSON *bitrateItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_BIT_RATE);
    if (nullptr == bitrateItem) {
        ERR("Parse bitrate failed.");
    } else {
        videoEncoderParam.bitrate = bitrateItem->valueint;
    }

    cJSON *gopItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_GOP);
    if (nullptr == gopItem) {
        ERR("Parse gop failed.");
    } else {
        videoEncoderParam.gopSize = gopItem->valueint;
    }

    cJSON *profileItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_PROFILE);
    if (nullptr == profileItem) {
        ERR("Parse profile failed.");
    } else {
        videoEncoderParam.profile = profileItem->valueint;
    }

    cJSON *rcModeItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_RC_MODE);
    if (nullptr == rcModeItem) {
        ERR("Parse rcmode failed.");
    } else {
        videoEncoderParam.rcMode = rcModeItem->valueint;
    }

    cJSON *keyFrameItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_KEY_FRAME);
    if (nullptr == keyFrameItem) {
        ERR("Parse keyframe failed.");
    } else {
        videoEncoderParam.keyFrame = keyFrameItem->valueint;
    }

    cJSON *widthItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_WIDTH);
    if (nullptr == widthItem) {
        ERR("Parse width failed.");
    } else {
        videoEncoderParam.width = widthItem->valueint;
    }

    cJSON *heightItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_HEIGHT);
    if (nullptr == heightItem) {
        ERR("Parse height failed.");
    } else {
        videoEncoderParam.height = heightItem->valueint;
    }

    cJSON *encoderTypeItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_ENCODER_TYPE);
    if (nullptr == encoderTypeItem) {
        ERR("Parse encoder type failed.");
    } else {
        videoEncoderParam.encoderType = static_cast<EncodeType>(encoderTypeItem->valueint);
    }

    EncodeType encodeType = VideoAgent::GetInstance()->GetEncodeType();
    if (videoEncoderParam.encoderType != encodeType) {
        ERR("Encode type is different from current worker encode type.");
        videoEncoderParam.encoderType = encodeType;
    }

    cJSON *frameTypeItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_FRAME_TYPE);
    if (nullptr == frameTypeItem) {
        ERR("Parse frame type failed.");
    } else {
        videoEncoderParam.frameType = static_cast<EncodeFrameType>(frameTypeItem->valueint);
    }

    // 池化cpu软编，设置为0自动根据绑核设置
    videoEncoderParam.cpuCnt = 0;
    INFO("Set thread count 0 on codec pool cpu encode.");

    // 池化cpu软编，使用slice编码
    videoEncoderParam.sliceBased = 1;
    INFO("Set thread type slice on codec pool cpu encode.");

    cJSON *disrepeatItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_DISREPEAT);
    if (nullptr == disrepeatItem) {
        ERR("Parse disrepeat flag failed.");
    } else {
        videoEncoderParam.disrepeat = disrepeatItem->valueint;
    }

    cJSON *presetItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_PRESET);
    if (nullptr == presetItem) {
        ERR("Parse preset failed.");
    } else {
        videoEncoderParam.preset = presetItem->valuestring;
    }

    cJSON *tuneItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_TUNE);
    if (nullptr == tuneItem) {
        ERR("Parse tune failed.");
    } else {
        videoEncoderParam.tune = tuneItem->valuestring;
    }

    cJSON *repeatFpsItem = cJSON_GetObjectItem(cjsonConf, CONF_KEY_REPEAT_FPS);
    if (nullptr == repeatFpsItem) {
        ERR("Parse repeat fps failed.");
    } else {
        videoEncoderParam.repeatFPS = repeatFpsItem->valueint;
    }
    cJSON_Delete(cjsonConf);
    return true;
}

void VideoEncoder::InitEncodeParam(uint8_t* packet, uint32_t len)
{
    std::string conf(reinterpret_cast<char *>(packet), len);
    VideoEncoderParam videoEncoderParam;
    if (!ParseCjsonConfig(conf, videoEncoderParam)) {
        ERR("Parse cJson config failed.");
        return;
    }
    INFO("len is :%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s", len, videoEncoderParam.frameRate, videoEncoderParam.bitrate, videoEncoderParam.gopSize, 
        videoEncoderParam.profile, videoEncoderParam.rcMode, videoEncoderParam.keyFrame, videoEncoderParam.width, videoEncoderParam.height, videoEncoderParam.encoderType, 
        videoEncoderParam.frameType, videoEncoderParam.cpuCnt, videoEncoderParam.sliceBased, videoEncoderParam.disrepeat, videoEncoderParam.repeatFPS,
        videoEncoderParam.preset.c_str(), videoEncoderParam.tune.c_str());
    uint8_t errorCode = 0;
    errorCode = VideoAgent::GetInstance()->ParametersValidation(videoEncoderParam.encoderType, videoEncoderParam.frameType, videoEncoderParam.width, videoEncoderParam.height, videoEncoderParam.frameRate);
    if (errorCode) {
        ERR("requested and supported encoding pararmeters are not equal, please check!");
        SendErrorCode(errorCode);
        return;
    }
    if (videoEncoderParam.frameRate == FRAMERATE_30_WITHOUT_REPEAET) {
        videoEncoderParam.frameRate = FRAMERATE_30;
    } else if (videoEncoderParam.frameRate == FRAMERATE_60_WITHOUT_REPEAET) {
        videoEncoderParam.frameRate = FRAMERATE_60;
    }
    if (this->m_videoEngine == nullptr) {
        this->m_param = videoEncoderParam;
        this->m_rcMode = videoEncoderParam.rcMode;
        this->m_videoEngine = new VideoEngine();
        if (m_videoEngine == nullptr ||
            VMI_SUCCESS != m_videoEngine->SetOpt("rcMode", std::to_string(this->m_rcMode)) ||
            VMI_SUCCESS != m_videoEngine->RegisterEncoderCallback(SendFrame) ||
            VMI_SUCCESS != m_videoEngine->InitEncoder(videoEncoderParam) ||
            VMI_SUCCESS != m_videoEngine->StartEncoder()) {
            ERR("failed to start encoder engine");
            std::thread callbackThread(
                [this]() -> void {
                    this->m_callback();
                    return;
                });
            if (callbackThread.joinable()) {
                callbackThread.detach();
            }
            return;
        }
    } else {
        this->m_keyFrame = videoEncoderParam.keyFrame;
        if (this->m_param.width != videoEncoderParam.width || this->m_param.height != videoEncoderParam.height) {
             //初始化编码器
            this->m_param = videoEncoderParam;
            this->m_rcMode = videoEncoderParam.rcMode;
            if (VMI_SUCCESS != m_videoEngine->DestroyEncoder() ||
                VMI_SUCCESS != m_videoEngine->SetOpt("rcMode", std::to_string(this->m_rcMode)) ||
                VMI_SUCCESS != m_videoEngine->RegisterEncoderCallback(SendFrame) ||
                VMI_SUCCESS != m_videoEngine->InitEncoder(this->m_param) ||
                VMI_SUCCESS != m_videoEngine->StartEncoder()){
                ERR("failed to start encoder engine");
                std::thread callbackThread(
                [this]() -> void {
                    this->m_callback();
                    return;
                });
                if (callbackThread.joinable()) {
                    callbackThread.detach();
                }
            }
            INFO("width & height changed succ.......");
        } else if (this->m_keyFrame) {
            if (m_videoEngine->SetEncoderKeyFrame() != VMI_SUCCESS) {
                ERR("SetKeyFrame failed");
            }
        } else {
            int rcMode = videoEncoderParam.rcMode;
            if (this->m_rcMode != rcMode) {
                this->m_rcMode = rcMode;
                INFO("Start to set rcMode");
                m_videoEngine->SetOpt("rcMode",std::to_string(rcMode));
            }
            INFO("Start to set param,bitrate is:%d",videoEncoderParam.bitrate);
            m_videoEngine->SetEncoderParam(videoEncoderParam);
        }
    }
}

/**
 * @功能描述：调用编码引擎进行编码
 */
void VideoEncoder::Handle(uint8_t* packet, uint32_t len)
{
    VideoParamExtMsg* param = reinterpret_cast<VideoParamExtMsg *>(packet);
    param->netToHostOrder();
    this->m_repeatDataStartTs = param->startCaptureTs;
    this->m_repeatDataEndTs = param->endCaptureTs;
    this->m_lastFrameEncodeTs = GetCurrentTimeUs();

    int headerSize = sizeof(VideoParamExtMsg);
    DBG("ts1 is %lld, ts2 is %lld", param->startCaptureTs, param->endCaptureTs);
    m_videoEngine->GetEncoderStatus(this->m_status);
    if (this->m_status == EngineStat::VMI_ENCODE_ENGINE_RUNNING) {
        VideoParamExt videoParamExt = {param->startCaptureTs, param->endCaptureTs, param->startEncodeTs, param->endEncodeTs};
        int encRet = m_videoEngine->EncodeOneFrame(packet + headerSize, (len-headerSize), videoParamExt);
        if (encRet != VMI_SUCCESS) {
            ERR("encode failed");
        } else {
            this->m_lastFrameEncodeTs = GetCurrentTimeUs();
        }
    } else {
        ERR("VideoEngine status is:%d", this->m_status);
    }
}

/**
 * @功能描述：调用编码引擎进行补帧
 */
void VideoEncoder::HandleRepeat()
{
    if (!CanDoRepeat()) {
        (void)usleep(SLEEP_FOR_ENCODE);
        return;
    }

    uint64_t timeMs = GetCurrentTimeMs();
    unsigned int fps = m_videoEngine->getCurrentFPS(timeMs);
    if (fps >= m_param.repeatFPS) {
        DBG("fps is %u, repeat fps is %d", fps, m_param.repeatFPS);
        (void)usleep(SLEEP_FOR_ENCODE);
        return;
    }

    long timeUs1 = GetCurrentTimeUs();
    // 既要确保FPS, 又要确保时间间距。
    if (timeUs1 - ONE_SECOND_TO_US / m_param.repeatFPS < m_lastFrameEncodeTs) {
        DBG("do not need to repeat now");
        (void)usleep(SLEEP_FOR_ENCODE);
        return;
    }

    m_lastFrameEncodeTs = timeUs1;
    VideoParamExt repeatParam = {m_repeatDataStartTs,
                                m_repeatDataEndTs, (uint64_t)GetCurrentTimeMs(), 0};
    int encRet = 0;
    {
        std::lock_guard<std::mutex> lock(m_lastFrameLock);
        int headerSize = sizeof(VideoParamExtMsg);
        m_videoEngine->EncodeRepeatOneFrame(m_lastFrame.first + headerSize,
                                                            m_lastFrame.second - headerSize, repeatParam);
    }
    
    if (encRet != VMI_SUCCESS) {
        ERR("Encode failed");
        (void)usleep(SLEEP_FOR_ENCODE);
        return;
    } else {
        if (fps == 0) { m_lastFrameEncodeTs = GetCurrentTimeUs(); }
    }
}

bool VideoEncoder::CanDoRepeat()
{
    if (m_param.disrepeat) {
        DBG("Repeat frame closed.");
        return false;
    }
    if (IsLastFrameNotReady()) {
        DBG("Repeat data failed: data is nullptr");
        return false;
    }

    if (m_videoEngine == nullptr || m_status != EngineStat::VMI_ENCODE_ENGINE_RUNNING) {
        INFO("video engine is not running.");
        return false;
    }
    return true;
}

void VideoEncoder::UpdateLastFrameData(std::pair<uint8_t*, uint32_t> &yuvData)
{
    std::lock_guard<std::mutex> lock(m_lastFrameLock);
    // 分辨率有变化, 更新用于补帧的YUV
    uint32_t dataLen = yuvData.second;
    if (m_lastFrame.second != dataLen) {
        if (m_lastFrame.first != nullptr) {
            VmiFreeBuffer(m_lastFrame.first);
        }
        m_lastFrame.first = reinterpret_cast<uint8_t *>(VmiAllocBuffer(dataLen));
        if (m_lastFrame.first == nullptr) {
            ERR("VmiAllocBuffer failed");
            m_lastFrame.second = 0;
            return;
        }
        m_lastFrame.second = dataLen;
    }

    errno_t errCode = memcpy_s(m_lastFrame.first, dataLen, yuvData.first, dataLen);
    if (errCode != EOK) {
        ERR("Backup last frame failed, error : %d.", errCode);
    }
}

void VideoEncoder::ClearLastFrame()
{
    std::lock_guard<std::mutex> lock(m_lastFrameLock);
    if (m_lastFrame.second != 0) {
        m_lastFrame.second = 0;
    }
    if (m_lastFrame.first != nullptr) {
        VmiFreeBuffer(m_lastFrame.first);
        m_lastFrame.first = nullptr;
    }
}

bool VideoEncoder::IsLastFrameNotReady()
{
    std::lock_guard<std::mutex> lock(m_lastFrameLock);
    return m_lastFrame.second == 0 || m_lastFrame.first == nullptr;
}

void VideoEncoder::AddVideoDataToQueue(VideoData &videoData)
{
    std::lock_guard<std::mutex> lock(m_queueLock);
    m_encodeQueue.push(videoData);
    if (videoData.dataType == VMIMsgType::VideoStreamYuv) {
        m_YUVCount++;
    }
}

size_t VideoEncoder::GetEncodeQueueYUVCount()
{
    std::lock_guard<std::mutex> lock(m_queueLock);
    return m_YUVCount;
}

VideoData VideoEncoder::PopEncodeQueue()
{
    std::lock_guard<std::mutex> lock(m_queueLock);
    VideoData videoData = m_encodeQueue.front();
    m_encodeQueue.pop();
    if (videoData.dataType == VMIMsgType::VideoStreamYuv) {
        m_YUVCount--;
    }
    return videoData;
}

void VideoEncoder::ClearEncodeQueue()
{
    std::lock_guard<std::mutex> lock(m_queueLock);
    while (!m_encodeQueue.empty()) {
        VideoData videoData = m_encodeQueue.front();
        m_encodeQueue.pop();
        VmiFreeBuffer(videoData.data);
    }
    m_YUVCount = 0;
}

bool VideoEncoder::IsQueueEmpty()
{
    std::lock_guard<std::mutex> lock(m_queueLock);
    return m_encodeQueue.empty();
}

void VideoEncoder::DestroyVideoEngine()
{
    INFO("DestroyVideoEngine start");
    if (m_videoEngine != nullptr) {
        if (m_videoEngine->DestroyEncoder() != 0){
            ERR("DestroyEncoder failed");
        }
        m_videoEngine = nullptr;
    }
}

/**
 * @功能描述：编码引擎回调函数
 */
int VideoEncoder::SendFrame(uint8_t* data, int length, VideoParamExt& param)//lint !e1072
{
    int ret = -1;
    uint8_t* pPkt;
    VMIMsgType type = VMIMsgType::VideoStreamH264;

    uint64_t startCaptureTsData[1] = {hton64(param.startCaptureTs)};
    uint64_t endCaptureTsData[1] = {hton64(param.endCaptureTs)};
    uint64_t startEncodeTsData[1] = {hton64(param.startEncodeTs)};
    uint64_t endEncodeTsData[1] = {hton64(param.endEncodeTs)};
    
    TLVPacket startCaptureTsPacket = {TLV_TYPE_START_CAP_TS, sizeof(param.startCaptureTs), reinterpret_cast<uint8_t*>(startCaptureTsData)};
    TLVPacket endCaptureTsPacket = {TLV_TYPE_END_CAP_TS, sizeof(param.endCaptureTs), reinterpret_cast<uint8_t*>(endCaptureTsData)};
    TLVPacket startEncodeTsPacket = {TLV_TYPE_START_ENCODE_TS, sizeof(param.startEncodeTs), reinterpret_cast<uint8_t*>(startEncodeTsData)};
    TLVPacket endEncodeTsPacket = {TLV_TYPE_END_ENCODE_TS, sizeof(param.endEncodeTs), reinterpret_cast<uint8_t*>(endEncodeTsData)};
    TLVPacket streamDataPacket;
    streamDataPacket = {TLV_TYPE_STREAM, (uint32_t)length, data};

    std::vector<TLVPacket> packetVector;
    packetVector.push_back(startCaptureTsPacket);
    packetVector.push_back(endCaptureTsPacket);
    packetVector.push_back(startEncodeTsPacket);
    packetVector.push_back(endEncodeTsPacket);
    packetVector.push_back(streamDataPacket);

    int tlLength = packetVector.size() * (sizeof(startCaptureTsPacket.tlvType) + sizeof(startCaptureTsPacket.tlvLength));
    int vLength = startCaptureTsPacket.tlvLength + endCaptureTsPacket.tlvLength
                + startEncodeTsPacket.tlvLength + endEncodeTsPacket.tlvLength + streamDataPacket.tlvLength;
    int dataSize = tlLength + vLength;
    pPkt = new(std::nothrow) uint8_t[dataSize + sizeof(StreamMsgHead)];
    if (pPkt == nullptr) {
        ERR("new failed");
    }
    std::vector<TLVPacket>::iterator iterPacket;
    int memcpyStartPos = sizeof(StreamMsgHead);
    for (iterPacket = packetVector.begin(); iterPacket < packetVector.end(); iterPacket++) {
        int iterTlLength = sizeof(iterPacket->tlvType) + sizeof(iterPacket->tlvLength);
        int iterVLegnth = iterPacket->tlvLength;
        iterPacket->tlvLength = htonl(iterPacket->tlvLength);
        if (memcpy_s(pPkt + memcpyStartPos, iterTlLength, reinterpret_cast<void*> (&(iterPacket->tlvType)), iterTlLength) != EOK) {        // 拷贝TL信息
            ERR("memcpy_s TL data failed, size: %d", iterTlLength);
            delete []pPkt;
            return ret;
        }
        memcpyStartPos += iterTlLength;
        if (memcpy_s(pPkt + memcpyStartPos, iterVLegnth, reinterpret_cast<void*> (iterPacket->tlvData), iterVLegnth) != EOK) {        // 拷贝V信息
            ERR("memcpy_s V data failed, size: %d", iterVLegnth);
            delete []pPkt;
            return ret;
        }
        memcpyStartPos += iterVLegnth;
    }
    ret = VideoSocketAgent::GetInstance()->Send(type, *reinterpret_cast<StreamMsgHead*>(pPkt), dataSize);
    delete []pPkt;
    return ret;
}

int VideoEncoder::SendErrorCode(uint8_t errorCode) {
    int ret = -1;
    uint8_t* pPkt;
    VMIMsgType type = VMIMsgType::VideoEncodeConf;
    int dataSize = 1;
    pPkt = new(std::nothrow) uint8_t[dataSize + sizeof(StreamMsgHead)];
    if (pPkt == nullptr) {
        ERR("new failed");
    }
    if (memcpy_s(pPkt + sizeof(StreamMsgHead), dataSize, &errorCode, dataSize) != EOK) {
        ERR("memcpy_s failed");
        delete []pPkt;
        return ret;
    }
    ret = VideoSocketAgent::GetInstance()->Send(type, *reinterpret_cast<StreamMsgHead*>(pPkt), dataSize);
    delete []pPkt;
    return ret;
}
